package bll

import (
	"context"
	"fmt"
	"gorm.io/gorm"
	log "manager/collector/logger"
	"manager/errors"

	"manager/event"
	"manager/model"
	"manager/model/entity"
	"manager/store"
	"manager/store/postgres"
	"time"
)

type firmwaresTactic struct {
	iFirmwaresTactic store.IFirmwaresTactic
	iFirmwaresRecord store.IFirmwaresRecord
	iUpgradeRecord   store.IUpgradeRecord
	iFirmware        store.IFirmware
	iEbike           store.IEbike
}

var FirmwaresTactic = &firmwaresTactic{
	iFirmwaresTactic: postgres.FirmwaresTactic,
	iFirmwaresRecord: postgres.FirmwaresRecord,
	iUpgradeRecord:   postgres.UpgradeRecord,
	iFirmware:        postgres.Firmware,
	iEbike:           postgres.Ebike,
}

func (a *firmwaresTactic) init() func() {
	return func() {}
}

func (a *firmwaresTactic) onEvent(*event.Data) {}

// Create 创建
func (a *firmwaresTactic) Create(ctx context.Context, in *model.FirmwaresTacticCreateRequest) error {
	var (
		err  error
		id   int64
		fety *entity.Firmware
		//cnt  int64
	)
	//判断是否有冲突得升级策略
	//cnt, err = checkForConflictsPlans(in)
	//if err != nil {
	//	return err
	//}
	//if cnt > 0 {
	//	return errors.OTAUpgradePlanConflict.Error()
	//}
	fety, err = a.iFirmware.Find(ctx, &model.FirmwareInfoRequest{Id: in.FirmwareId})
	if err != nil || err == gorm.ErrRecordNotFound {
		log.Error(err)
		return errors.NoData.Error()
	}
	err = a.iFirmwaresTactic.ExecTransaction(ctx, func(ctx context.Context) error {
		//立即推送,则取当前时间
		if in.UpgradeType == 0 {
			in.ReleaseTime = time.Now().Unix()
		}
		in.Status = 3

		in.Count, err = getFirmwaresTacticDeviceCount(in.ExecRange, in.SnCode, in.EbikesType)
		if err != nil {
			log.Error(err)
			return err
		}

		// 构建创建现场数据
		c := buildFirmwaresTactic(in)
		id, err = a.iFirmwaresTactic.Create(ctx, c)
		if err != nil {
			log.Error(err)
			return err
		}
		if in.ExecRange == 1 {
			_, err = a.iFirmwaresRecord.Create(ctx, &entity.FirmwaresRecord{
				FirmwareId:    in.FirmwareId,
				TacticsId:     id,
				Version:       fety.Version,
				FirmwaresName: fety.Name,
				EbikesType:    in.EbikesType,
				CreatedAt:     time.Now().Unix(),
			})
		} else if in.ExecRange == 2 {
			for _, s := range in.SnCode {
				_, err = a.iUpgradeRecord.Create(ctx, &entity.UpgradeRecord{
					FirmwareId:    in.FirmwareId,
					TacticsId:     id,
					Version:       fety.Version,
					FirmwaresName: fety.Name,
					SnCode:        s,
					CreatedAt:     time.Now().Unix(),
				})
			}
		}
		return nil
	})
	return err
}

// Update 更新
func (a *firmwaresTactic) Update(ctx context.Context, in *model.FirmwaresTacticUpdateRequest) error {
	var (
		dict       = make(map[string]interface{})
		err        error
		fety       *entity.Firmware
		ebikeCount int
	)

	updateAt := time.Now().Unix()
	in.UpdatedAt = &updateAt

	if in.FirmwareId != nil {
		dict["firmware_id"] = in.FirmwareId
	}

	if in.ReleaseTime != nil {
		dict["release_time"] = in.ReleaseTime
	}

	if in.ReleaseType != nil {
		dict["release_type"] = in.ReleaseType
	}

	if in.UpgradeType != nil {
		dict["upgrade_type"] = in.UpgradeType
	}

	if in.ExecRange != nil {
		dict["exec_range"] = in.ExecRange
	}

	if in.Status != nil {
		dict["status"] = in.Status
	}

	if in.Desc != nil {
		dict["desc"] = in.Desc
	}

	if in.UpdatedAt != nil {
		dict["updated_at"] = in.UpdatedAt
	}
	// do other update here

	//todo 判断是否有冲突得升级策略
	fety, err = a.iFirmware.Find(ctx, &model.FirmwareInfoRequest{Id: *in.FirmwareId})
	if err != nil || err == gorm.ErrRecordNotFound {
		log.Error(err)
		return errors.NoData.Error()
	}
	err = a.iFirmwaresTactic.ExecTransaction(ctx, func(ctx context.Context) error {
		ebikeCount, err = getFirmwaresTacticDeviceCount(*in.ExecRange, in.SnCode, in.EbikesType)
		if err != nil {
			log.Error(err)
			return err
		}
		dict["count"] = ebikeCount

		// 构建创建现场数据
		err = a.iFirmwaresTactic.Update(ctx, in.Id, dict)
		if err != nil {
			log.Error(err)
			return err
		}

		if *in.ExecRange == 1 {
			firmwaresRecordDict := make(map[string]interface{})
			firmwaresRecordDict["ebikes_type"] = in.EbikesType
			firmwaresRecordDict["firmware_id"] = in.FirmwareId
			firmwaresRecordDict["version"] = fety.Version
			firmwaresRecordDict["firmwares_name"] = fety.Name
			err = a.iFirmwaresRecord.UpdateByTacticsId(ctx, in.Id, firmwaresRecordDict)
			if err != nil {
				return err
			}
		} else if *in.ExecRange == 2 {
			err = a.iUpgradeRecord.DeleteByTacticsId(ctx, in.Id)
			if err != nil {
				return err
			}
			for _, s := range in.SnCode {
				_, err = a.iUpgradeRecord.Create(ctx, &entity.UpgradeRecord{
					FirmwareId:    *in.FirmwareId,
					TacticsId:     in.Id,
					Version:       fety.Version,
					FirmwaresName: fety.Name,
					SnCode:        s,
					CreatedAt:     time.Now().Unix(),
				})
			}
		}

		return nil
	})
	return err
}

// Delete 删除
func (a *firmwaresTactic) Delete(ctx context.Context, in *model.FirmwaresTacticDeleteRequest) error {
	ft, err := a.iFirmwaresTactic.Find(ctx, &model.FirmwaresTacticInfoRequest{Id: in.Id})
	if err != nil && err == gorm.ErrRecordNotFound {
		return errors.NoData.Error()
	}
	if ft == nil {
		return errors.NoData.Error()
	}
	err = a.iFirmwaresTactic.ExecTransaction(ctx, func(ctx context.Context) error {
		if ft.ExecRange == 2 {
			err = a.iUpgradeRecord.DeleteByTacticsId(ctx, in.Id)
			if err != nil {
				log.Error(err)
				return err
			}
		} else if ft.ExecRange == 1 {
			err = a.iFirmwaresRecord.DeleteByTacticsId(ctx, in.Id)
			if err != nil {
				log.Error(err)
				return err
			}
		}
		err = a.iFirmwaresTactic.Delete(ctx, in.Id)
		if err != nil {
			log.Error(err)
			return err
		}
		return nil
	})
	return err
}

// List 列表查询
func (a *firmwaresTactic) List(ctx context.Context, in *model.FirmwaresTacticListRequest) (*model.FirmwaresTacticListResponse, error) {
	var (
		err   error
		total int
		list  []*entity.FirmwaresTactic
		out   = &model.FirmwaresTacticListResponse{}
	)

	if total, list, err = a.iFirmwaresTactic.List(ctx, in); err != nil {
		return nil, err
	}

	out.Total = total
	out.List = model.FirmwaresTacticsEntityToDto(list)

	var tacticsIds []int64
	for i := 0; i < len(out.List); i++ {
		//if out.List[i].ExecRange == 2 {
		tacticsIds = append(tacticsIds, out.List[i].Id)
		//}
	}
	if len(tacticsIds) > 0 {
		var successMap map[int64]int
		if len(tacticsIds) > 0 {
			successMap = postgres.DeviceUpgradeRecode.GetTacticsSuccessCount(ctx, tacticsIds)
		}

		for i := 0; i < len(out.List); i++ {
			successCount := 0
			if v, ok := successMap[out.List[i].Id]; ok {
				successCount = v
			}
			progressStr := fmt.Sprintf("%v/%v", successCount, out.List[i].Count)
			if out.List[i].Count == 0 {
				progressStr = "-"
			}
			out.List[i].Progress = progressStr
		}
	}

	return out, nil
}

// Find 列表查询
func (a *firmwaresTactic) Find(ctx context.Context, in *model.FirmwaresTacticInfoRequest) (*model.FirmwaresTacticInfo, error) {
	var (
		err  error
		data *entity.FirmwaresTactic
		out  = &model.FirmwaresTacticInfo{}
	)

	if data, err = a.iFirmwaresTactic.Find(ctx, in); err != nil {
		return nil, err
	}

	out = model.FirmwaresTacticEntityToDto(data)
	return out, nil
}

func (a *firmwaresTactic) Terminate(ctx context.Context, in *model.FirmwaresTacticTerminateRequest) error {
	var (
		dict = make(map[string]interface{})
	)
	dict["status"] = 2
	dict["updated_at"] = time.Now().Unix()
	return a.iFirmwaresTactic.Update(ctx, in.Id, dict)
}

func (a *firmwaresTactic) FindByBike(ctx context.Context, in *model.FirmwaresFindByBikeRequest) (*model.FirmwaresFindByBikeResponse, error) {
	var out = &model.FirmwaresFindByBikeResponse{}
	list, err := a.iUpgradeRecord.FindByTacticsId(ctx, in.Id)
	if err != nil {
		log.Error(err)
		return nil, err
	}
	if len(list) <= 0 {
		return nil, err
	}
	s := make([]string, len(list))
	for i, record := range list {
		s[i] = record.SnCode
	}
	out.SnCode = &s
	return out, err
}

func (a *firmwaresTactic) FindByType(ctx context.Context, in *model.FirmwaresFindByTypeRequest) (*model.FirmwaresFindByTypeResponse, error) {
	fr, err := a.iFirmwaresRecord.Find(ctx, &model.FirmwaresRecordInfoRequest{TacticsId: &in.Id})
	if err != nil && err != gorm.ErrRecordNotFound {
		log.Error(err)
		return nil, err
	}
	if fr == nil || fr.TacticsId <= 0 {
		return nil, err
	}
	return &model.FirmwaresFindByTypeResponse{
		EbikesType: fr.EbikesType,
	}, err
}

func checkForConflictsPlans(in *model.FirmwaresTacticCreateRequest) (int64, error) {
	var (
		err    error
		cnt    int64
		typeId []int64
	)
	// 升级范围-正在运行-全部执行
	cnt, err = FirmwaresTactic.iFirmwaresTactic.CheckExistActivePlanByRange(0)
	if cnt > 0 {
		return cnt, nil
	}
	//配置车型查询-正在运行-车型配置
	if in.ExecRange == 1 {
		cnt, err = FirmwaresTactic.iFirmwaresRecord.CheckExistActivePlanByType(in.EbikesType)
		if cnt > 0 {
			return cnt, nil
		}
		//查看指定车辆中是否有配置该型号的车辆
		cnt, err = UpgradeRecord.iUpgradeRecord.CheckExistActivePlanByTypeId(in.EbikesType)
		if cnt > 0 {
			return cnt, nil
		}
	} else if in.ExecRange == 2 {
		cnt, err = UpgradeRecord.iUpgradeRecord.CheckExistActivePlanBySnCode(in.SnCode)
		if cnt > 0 {
			return cnt, nil
		}
		typeId, err = Ebike.iEbike.FindBySns(in.SnCode)
		if err != nil && err == gorm.ErrRecordNotFound {
			return 0, err
		}
		//根据snCode车辆型号查询指定型号配置中是否有该配置
		cnt, err = FirmwaresTactic.iFirmwaresRecord.CheckExistActivePlanByType(typeId)
		if cnt > 0 {
			return cnt, nil
		}
	} else {
		// 升级范围-正在运行
		cnt, err = FirmwaresTactic.iFirmwaresTactic.CheckExistActivePlanByRange(-1)
		if cnt > 0 {
			return cnt, nil
		}
	}
	return 0, err
}

// 获取指定升级范围设备数量
func getFirmwaresTacticDeviceCount(execRange int, snCode []string, ebikeType []int64) (int, error) {
	var (
		cnt int
	)

	//升级范围-全部执行
	if execRange == 0 {
		rsp, err := Ebike.iEbike.Count(context.Background())
		if err != nil {
			return 0, err
		}

		cnt = int(rsp.Total)
	} else if execRange == 1 {
		//升级范围-指定车型
		// 获取指定车型的车辆总数
		ebikeCount, err := Ebike.iEbike.GetCountByTypeId(context.Background(), ebikeType)
		if err != nil {
			log.Error(err)
			return 0, err
		}
		cnt = int(ebikeCount)
	} else {
		// 升级范围-指定车辆
		cnt = len(snCode)
	}
	return cnt, nil
}

// buildFirmwaresTactic 构建创建数据现场
func buildFirmwaresTactic(in *model.FirmwaresTacticCreateRequest) *entity.FirmwaresTactic {
	return &entity.FirmwaresTactic{

		FirmwareId: in.FirmwareId,

		ReleaseTime: in.ReleaseTime,

		ReleaseType: in.ReleaseType,

		UpgradeType: in.UpgradeType,

		ExecRange: in.ExecRange,

		Status: in.Status,

		Desc: in.Desc,

		Count: in.Count,

		CreatedAt: time.Now().Unix(),

		UpdatedAt: time.Now().Unix(),
	}
}
